package edu.bbu.bibliospring.backend.repository.beans;

import edu.bbu.bibliospring.backend.model.AbstractModel;
import edu.bbu.bibliospring.backend.repository.BaseRepository;
import edu.bbu.bibliospring.backend.repository.exception.BibliospringRepositoryException;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.List;

public abstract class BaseRepositoryBean <T extends AbstractModel, I> implements BaseRepository<T, I> {

    @PersistenceContext(unitName = "bibliospring-persistence")
    private EntityManager entityManager;

    private final Class<T> tClass;

    protected BaseRepositoryBean(Class<T> tC) {
        tClass = tC;
    }

    protected BaseRepositoryBean() {
        tClass = null;
    }

    @Override
    public List<T> getAll() throws BibliospringRepositoryException {
        try {
            final CriteriaBuilder cb = entityManager.getCriteriaBuilder ();
            final CriteriaQuery<T> criteriaQuery = cb.createQuery (tClass);
            final Root<T> rootEntry = criteriaQuery.from (tClass);
            final CriteriaQuery<T> all = criteriaQuery.select (rootEntry);
            final TypedQuery<T> allQuery = entityManager.createQuery (all);
            return allQuery.getResultList ();
        } catch (IllegalArgumentException | PersistenceException e) {
            throw new BibliospringRepositoryException ("Error in method getAll.", e);
        }
    }

    @Override
    public T getById(final I id) throws BibliospringRepositoryException {
        try {
            return entityManager.find(tClass, id);
        } catch (final PersistenceException pe) {

            throw new BibliospringRepositoryException("BaseRepositoryBean getById method!", pe);
        }
    }

    @Override
    public T save(final T item) throws BibliospringRepositoryException {
        try {
            entityManager.persist(item);
            entityManager.flush();
            return item;
        } catch (final PersistenceException pe) {
            throw new BibliospringRepositoryException("BaseRepositoryBean save method!", pe);
        }
    }

    @Override
    public T merge(T item) throws BibliospringRepositoryException {
        try {
            item = entityManager.merge(item);
            return item;
        } catch (final PersistenceException pe) {
            throw new BibliospringRepositoryException("BaseRepositoryBean save method!", pe);
        }
    }

    @Override
    public I delete(final T item) throws BibliospringRepositoryException {
        try {
            entityManager.remove(item);
        } catch (final Exception e) {
            throw new BibliospringRepositoryException("BaseRepositoryBean delete method", e);
        }
        return null;
    }
}
